CREATE OR REPLACE TYPE tipo_objeto AS OBJECT(
id NUMBER,
MAP MEMBER FUNCTION get_id RETURN NUMBER
)NOT FINAL NOT INSTANTIABLE;
/

CREATE OR REPLACE TYPE BODY tipo_objeto AS
MAP MEMBER FUNCTION get_id RETURN NUMBER IS
BEGIN
RETURN id;
END;
END;
/

CREATE OR REPLACE TYPE tipo_pessoa UNDER tipo_objeto(
nome VARCHAR2(100),
sexo CHAR,
data_nascimento DATE,
cpf VARCHAR2(14),
senha VARCHAR2(20),
foto BLOB,
MEMBER FUNCTION get_idade RETURN NUMBER,
MEMBER PROCEDURE set_sexo(novo_sexo CHAR),
MEMBER PROCEDURE set_data_nascimento(nova_data_nascimento DATE)
)NOT FINAL NOT INSTANTIABLE;
/

CREATE OR REPLACE TYPE BODY tipo_pessoa AS 
MEMBER FUNCTION get_idade RETURN NUMBER IS
BEGIN
RETURN SYSDATE - data_nascimento;
END;
MEMBER PROCEDURE set_sexo(novo_sexo CHAR) IS
BEGIN
sexo := novo_sexo;
END;
MEMBER PROCEDURE set_data_nascimento(nova_data_nascimento DATE) IS
BEGIN
data_nascimento := nova_data_nascimento;
END;
END;
/

CREATE OR REPLACE TYPE tipo_medico UNDER tipo_pessoa(
crefito VARCHAR2(13),
dados VARCHAR2(2000),
admin CHAR,
CONSTRUCTOR FUNCTION tipo_medico(nnome VARCHAR2, ncpf VARCHAR2, ncrefito VARCHAR2, ndados VARCHAR2, nsenha VARCHAR2, nfoto BLOB, nadmin CHAR) RETURN SELF AS RESULT
);
/

CREATE TYPE BODY tipo_medico AS
CONSTRUCTOR FUNCTION tipo_medico(nnome VARCHAR2, ncpf VARCHAR2, ncrefito VARCHAR2, ndados VARCHAR2, nsenha VARCHAR2, nfoto BLOB, nadmin CHAR) RETURN SELF AS RESULT IS
BEGIN
nome := nnome;
cpf := ncpf;
crefito := ncrefito;
dados := ndados;
senha := nsenha;
foto := nfoto;
admin := nadmin;
RETURN;
END;
END;
/

CREATE TABLE tabela_medico OF tipo_medico(
nome NOT NULL,
CONSTRAINT medico_cp PRIMARY KEY(id),
CONSTRAINT medico_cc1 UNIQUE(cpf),
CONSTRAINT medico_cc2 UNIQUE(crefito),
CONSTRAINT medico_admin CHECK(admin in('T','F'))
);
/

CREATE SEQUENCE seq_medico START WITH 1 INCREMENT BY 1;
/

CREATE OR REPLACE TRIGGER seq_medico_trigger
BEFORE INSERT ON tabela_medico FOR EACH ROW
BEGIN
    SELECT seq_medico.NEXTVAL INTO :NEW.id FROM DUAL;
END;
/

CREATE OR REPLACE TYPE tipo_entrada_livro_caixa UNDER tipo_objeto(
medico REF tipo_medico,
data DATE,
descricao VARCHAR2(2000),
valor NUMBER,
CONSTRUCTOR FUNCTION tipo_entrada_livro_caixa(nmedico REF tipo_medico, ndata DATE, ndescricao VARCHAR2, nvalor NUMBER) RETURN SELF AS RESULT
);
/

CREATE TYPE BODY tipo_entrada_livro_caixa AS
CONSTRUCTOR FUNCTION tipo_entrada_livro_caixa(nmedico REF tipo_medico, ndata DATE, ndescricao VARCHAR2, nvalor NUMBER) RETURN SELF AS RESULT IS
BEGIN
medico := nmedico;
data := ndata;
descricao := ndescricao;
valor := nvalor;
RETURN;
END;
END;
/

CREATE TABLE tabela_livro_caixa OF tipo_entrada_livro_caixa(
medico WITH ROWID REFERENCES tabela_medico,
CONSTRAINT livro_caixa_cp PRIMARY KEY(id)
);
/

CREATE SEQUENCE seq_livro_caixa START WITH 1 INCREMENT BY 1;
/

CREATE OR REPLACE TRIGGER seq_livro_caixa_trigger
BEFORE INSERT ON tabela_livro_caixa FOR EACH ROW
BEGIN
    SELECT seq_livro_caixa.NEXTVAL INTO :NEW.id FROM DUAL;
END;
/

CREATE OR REPLACE TYPE varray_contatos AS VARRAY(2) OF VARCHAR2(13);
/

CREATE OR REPLACE TYPE tipo_paciente UNDER tipo_pessoa(
endereco VARCHAR2(150),
email VARCHAR2(100),
contato varray_contatos,
profissao VARCHAR2(30),
observacao VARCHAR2(2000),
CONSTRUCTOR FUNCTION tipo_paciente(nnome VARCHAR2, nsexo CHAR, ndata_nascimento DATE, ncpf VARCHAR2, nsenha VARCHAR2, nfoto BLOB, nendereco VARCHAR2, nemail VARCHAR2, ncontato1 VARCHAR2, ncontato2 VARCHAR2, nprofissao VARCHAR2, nobservacao VARCHAR2) RETURN SELF AS RESULT
);
/

CREATE OR REPLACE TYPE BODY tipo_paciente AS
CONSTRUCTOR FUNCTION tipo_paciente(nnome VARCHAR2, nsexo CHAR, ndata_nascimento DATE, ncpf VARCHAR2, nsenha VARCHAR2, nfoto BLOB, nendereco VARCHAR2, nemail VARCHAR2, ncontato1 VARCHAR2, ncontato2 VARCHAR2, nprofissao VARCHAR2, nobservacao VARCHAR2) RETURN SELF AS RESULT IS
BEGIN
nome := nnome;
sexo := nsexo;
data_nascimento := ndata_nascimento;
cpf := ncpf;
senha := nsenha;
foto := nfoto;
endereco := nendereco;
email := nemail;
contato := varray_contatos(ncontato1, ncontato2);
profissao := nprofissao;
observacao := nobservacao;
RETURN;
END;
END;
/

CREATE TABLE tabela_paciente OF tipo_paciente(
nome NOT NULL,
CONSTRAINT paciente_cp PRIMARY KEY(id),
CONSTRAINT paciente_cc UNIQUE(cpf),
CONSTRAINT paciente_sexo CHECK(sexo IN ('M','F'))
);
/

CREATE SEQUENCE seq_paciente START WITH 1 INCREMENT BY 1;
/

CREATE OR REPLACE TRIGGER seq_paciente_trigger
BEFORE INSERT ON tabela_paciente FOR EACH ROW
BEGIN
    SELECT seq_paciente.NEXTVAL INTO :NEW.id FROM DUAL;
END;
/

CREATE OR REPLACE TYPE tipo_prontuario UNDER tipo_objeto(
tipo VARCHAR2(30),
anamnese VARCHAR2(2000),
conteudo VARCHAR2(2000)
);
/

CREATE OR REPLACE TYPE tipo_nested_prontuario AS TABLE OF tipo_prontuario;
/

CREATE OR REPLACE TYPE tipo_atendimento UNDER tipo_objeto(
medico number,
paciente number,
prontuarios tipo_nested_prontuario,
CONSTRUCTOR FUNCTION tipo_atendimento(nmedico NUMBER, npaciente NUMBER) RETURN SELF AS RESULT
);
/

CREATE OR REPLACE TYPE BODY tipo_atendimento AS
CONSTRUCTOR FUNCTION tipo_atendimento(nmedico NUMBER, npaciente NUMBER) RETURN SELF AS RESULT IS
BEGIN
medico := nmedico;
paciente := npaciente;
prontuarios := tipo_nested_prontuario();
RETURN;
END;
END;
/

CREATE TABLE tabela_atendimento OF tipo_atendimento(
CONSTRAINT atendimento_ce1 FOREIGN KEY(medico) REFERENCES tabela_medico ON DELETE CASCADE,
CONSTRAINT atendimento_ce2 FOREIGN KEY(paciente) REFERENCES tabela_paciente ON DELETE CASCADE,
CONSTRAINT atendimento_id UNIQUE(id),
CONSTRAINT atendimento_cp PRIMARY KEY(medico, paciente)
)NESTED TABLE prontuarios STORE AS tabela_nested_prontuario;
/

CREATE SEQUENCE seq_prontuario START WITH 1 INCREMENT BY 1;
/

CREATE SEQUENCE seq_atendimento START WITH 1 INCREMENT BY 1;
/

CREATE OR REPLACE TRIGGER seq_atendimento_trigger
BEFORE INSERT ON tabela_atendimento FOR EACH ROW
BEGIN
    SELECT seq_atendimento.NEXTVAL INTO :NEW.id FROM DUAL;
END;
/

CREATE OR REPLACE TYPE tipo_compromisso UNDER tipo_objeto(
medico REF tipo_medico,
paciente REF tipo_paciente,
datahorario TIMESTAMP,
descricao VARCHAR2(2000),
CONSTRUCTOR FUNCTION tipo_compromisso(nmedico REF tipo_medico, npaciente REF tipo_paciente, ndatahorario TIMESTAMP, ndescricao VARCHAR2) RETURN SELF AS RESULT
);
/

CREATE OR REPLACE TYPE BODY tipo_compromisso AS
CONSTRUCTOR FUNCTION tipo_compromisso(nmedico REF tipo_medico, npaciente REF tipo_paciente, ndatahorario TIMESTAMP, ndescricao VARCHAR2) RETURN SELF AS RESULT IS
BEGIN
medico := nmedico;
paciente := npaciente;
datahorario := ndatahorario;
descricao := ndescricao;
RETURN;
END;
END;
/

CREATE TABLE tabela_compromisso OF tipo_compromisso(
medico WITH ROWID REFERENCES tabela_medico,
paciente WITH ROWID REFERENCES tabela_paciente,
CONSTRAINT compromisso_cp PRIMARY KEY(id)
);
/

CREATE SEQUENCE seq_compromisso START WITH 1 INCREMENT BY 1;
/

CREATE OR REPLACE TRIGGER seq_compromisso_trigger
BEFORE INSERT ON tabela_compromisso FOR EACH ROW
BEGIN
    SELECT seq_compromisso.NEXTVAL INTO :NEW.id FROM DUAL;
END;
/

CREATE OR REPLACE TYPE tipo_modelo_prontuario UNDER tipo_objeto(
tipo VARCHAR2(30),
conteudo VARCHAR2(2000),
CONSTRUCTOR FUNCTION tipo_modelo_prontuario(ntipo VARCHAR2, nconteudo VARCHAR2) RETURN SELF AS RESULT
);
/

CREATE OR REPLACE TYPE BODY tipo_modelo_prontuario AS
CONSTRUCTOR FUNCTION tipo_modelo_prontuario(ntipo VARCHAR2, nconteudo VARCHAR2) RETURN SELF AS RESULT IS
BEGIN
tipo := ntipo;
conteudo := nconteudo;
RETURN;
END;
END;
/

CREATE TABLE tabela_modelo_prontuario OF tipo_modelo_prontuario(
CONSTRAINT modelo_prontuario_cp PRIMARY KEY(id)
);
/

CREATE SEQUENCE seq_modelo_prontuario START WITH 1 INCREMENT BY 1;
/

CREATE OR REPLACE TRIGGER seq_modelo_prontuario_trigger
BEFORE INSERT ON tabela_modelo_prontuario FOR EACH ROW
BEGIN
    SELECT seq_modelo_prontuario.NEXTVAL INTO :NEW.id FROM DUAL;
END;
/